﻿using SLP;
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;

namespace MsiCustomize
{
    [Serializable]
    public class MstProject : INotifyPropertyChanged, INotifyCollectionChanged
    {
        /// <summary>
        /// To support INotifyPropertyChanged events
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>
        /// To support INotifyCollectionChanged events
        /// </summary>
        public event NotifyCollectionChangedEventHandler CollectionChanged;

        /// <summary>
        /// To support INotifyPropertyChanged events
        /// </summary>
        /// <param name="PropertyName">Name of property that changed</param>
        private void OnChanged(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
                _Modified = true;
            }
        }
        /// <summary>
        /// To support INotifyCollectionChanged events - ALso triggers PropertyChanged events
        /// </summary>
        private void OnCollectionChanged(string PropertyChanged, object sender, NotifyCollectionChangedEventArgs e)
        {
            if (CollectionChanged!=null) CollectionChanged(sender, e);
            OnChanged(PropertyChanged);  // also sets _Modified flag
        }

        /// <summary>
        /// Set in OnChaned when a property is modified
        /// </summary>
        private bool _Modified;
        /// <summary>
        /// Do we need to save the project / Re-generate the MST / CAB Files?
        /// </summary>
        public bool HasPendingChanges { get { return _Modified; } }

        /// <summary>
        /// Project File Name - used as a helper for the Save function
        /// </summary>
        public string FileName;

        string _Name;
        /// <summary>
        /// Name of the project / Generated MST File
        /// </summary>
        public string ProjectName
        {
            get { return _Name; }
            set { if (value != null && _Name != value) { _Name = value; OnChanged("ProjectName"); } }
        }

        string _Feature;
        /// <summary>
        /// Name of the new Feature (Must not already exist in the Original MSI)
        /// </summary>
        public string FeatureName
        {
            get { return _Feature; }
            set { if (value != null && _Feature != value) { _Feature = value; OnChanged("FeatureName"); } }
        }

        // not sure if this is needed - may generate a TEMP folder and use that when generating new MSI / MST / CAB files
        string _WorkFolder;
        public string WorkingFolder
        {
            get { return String.IsNullOrEmpty(_WorkFolder) ? _MsiFolder : _WorkFolder; }
            set { if (value != null && _WorkFolder != value) { _WorkFolder = value; OnChanged("WorkingFolder"); } }
        }

        // not sure if this is really needed at this time as it could be extrapolated from _MsiName
        string _MsiFolder;
        public string MsiFolder
        {
            get { return _MsiFolder; } // could be { return System.IO.Path.GetDirecotryName(_MsiFileName); }
            set { if (value != null && _MsiFolder != value) { _MsiFolder = value; OnChanged("MsiFolder"); } }
        }

        string _MsiName;
        public string MsiFileName
        {
            get { return _MsiName; }
            set { if (value != null && _MsiName != value) { _MsiName = value; OnChanged("MsiFileName"); } }
        }

        // this property needs to be expanded to allow for source and target and allow for INotifyPropertyChanged events
        // suggest a new class that has Source PathName, Target PathName and other properties based on both Directory and File Tables
        ObservableCollection<string> _Files;
        public ObservableCollection<string> AdditionalFiles
        {
            get { return _Files; }  // set may need to be modified to validate that a change has been made
            set { if (value != null && _Files != value) { _Files = value; OnChanged("AdditionalFiles"); } }
        }


        /// <summary>
        /// Full HKEY Registry Path, Value Name, Value Data
        /// </summary>
        MsiRegistryItemCollection _RegistryItems;
        public MsiRegistryItemCollection RegistryItems
        {
            get { return _RegistryItems; }
            set { if (value != null && _RegistryItems != value) { _RegistryItems = value; OnChanged("RegistryItems"); } }
        }

        MsiPropertyCollection _Prop;
        public MsiPropertyCollection ProjectProperties 
        {
            get { return _Prop; }   
            set { if (value != null && _Prop != value) { _Prop = value; OnChanged("ProjectProperties"); } }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public MstProject()
        {            
            _Files = new ObservableCollection<string>();
            _Files.CollectionChanged += _Files_CollectionChanged;
            _RegistryItems = new MsiRegistryItemCollection();
            _RegistryItems.CollectionChanged += _RegistryItems_CollectionChanged;
            _Prop = new MsiPropertyCollection();
            _Prop.CollectionChanged += _Prop_CollectionChanged;
            _Modified = false;
            // TODO - suggest another property to allow for "Active Setup" options (Per-User options for a Per-Machine install)
        }

        private void _Prop_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            OnCollectionChanged("ProjectProperties", ProjectProperties, e);
        }

        private void _RegistryItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            OnCollectionChanged("RegistryItems", RegistryItems, e);
        }

        private void _Files_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            OnCollectionChanged("AdditionalFiles", AdditionalFiles, e);
        }

        public static MstProject Load(string Filename)
        {
            MstProject mst = XML.Load<MstProject>(Filename);
            mst.FileName = Filename;
            return mst;            
        }

        public void Save(string Filename = null)
        {
            if (Filename != null) FileName = Filename;
            XML.SaveCompressed(this,FileName);
            _Modified = false;
        }
    }
}
